\section{Desarrollo}

En el presente trabajo se realizó una implementación del conjunto del Mandelbrot con aritmética de punto flotante de precisión variable.\\

Para desarrollar esto se tuvo en cuentas las consideraciones que se listan a continuación.

\subsection{Aritmética}

La aritmética que se ha optado por elegir para la representación del conjunto de los números reales es utilizar una aritmética de punto flotante con precisión dinámica en base 256 para tener la mayor cantidad de números a representar posibles.

\subsubsection{Normalización}

Decidimos utilizar una normalización para la representación de los números. Esto significa que cada número representado con nuestra estructura debe tener las siguientes condiciones. Se lleva el signo de la mantisa aparte.\\

Para la mantisa se tomara que es la parte decimal de el número \emph{``0,mantisa''} y también se tendrá la precisión actual y el exponente de la base tomada.\\

Entonces, sea $x$ el número representado, su representación queda como:
$$ x = 0,d_1 d_2 ... d_n * b^e$$

Siendo, $d_i$ el i-ésimo elemento de la mantisa, con $i \in \{0..precision\}$ y $d_0$ el dígito más significativo. Con $b$ siendo el exponente adoptado y $e$ el actual exponente.

Hay que tener en cuenta que $d_0 > 0$ y que $d_n > 0$ de esta forma tenemos una representación única de la mantisa y utiliza la mínima cantidad de dígitos posibles.

\subsubsection{Signo}

Se utiliza un indicador sobre la mantisa para poder representar tanto a números positivos como a números negativos.

\subsubsection{Precisión Dinámica}

Sobre la precisión de la mantisa, se decidió implementar una mantisa de precisión dinámica. Esto significa que a medida que se van sumando o multiplicando un número con otros, la mantisa aumenta o reduce su tamaño para ajustarse a la precisión máxima.

La idea de esto es poder representar los números con el menor error posible. De hecho, salvo por un tema en el parseo de los números, el error que se comete en las operaciones es nulo.

Respecto del parseo sucede que al hacer el cambio de base 10 a base 256, existen números racionales en base 10 que al ser transformados tienen representación periódica.

Para poder implementar una mantisa dinámica, se debió tener en cuenta como se ve afectada la precisión de la misma con las diferentes operaciones.\\

En el caso de la suma el pseudocódigo es: \\

\begin{verbatim}
Suma(Float a, Float b){

si(a.precisión > b.precisión) 
      {extenderPrecision(b,a.precisión) }
si(a.precisión < b.precisión) 
      { extenderPrecision(a,b.precisión) }
resultado = sumarDigitoADigito(a,b) 
normalizar(resultado) 
}
\end{verbatim}

De esta manera la precisión pasa a ser a lo sumo la máxima entre entre a y b, tal vez más uno en caso
de que llegue a haber carry en el dígito más significativo, por ejemplo $9,9 + 0,1$.\\\\

En el caso de la multiplicación el pseudocódigo para mantener la mantisa dinámica es:\\

\begin{verbatim}
Multiplicar(Float a, Float b){

si(a.precisión >= b.precisión) 
      { extenderPrecision(b,a.precisión) }
si(a.precisión < b.precisión) 
      { extenderPrecision(a,b.precisión) }
result.precisión = 2*a.precisión;
multiplicar(a,b,result)
normalizar(result)
}
\end{verbatim}

De esta forma la mantisa queda a lo sumo como el doble de la precisión del máximo número más 1 (en caso de carry).\\
En ambos casos la función normalizar se encarga de dejar el resultado de acuerdo a lo descripto 
en la sección previa "Normalización".

\subsubsection{Base y Exponente}

Para el exponente, se decidió utilizar una variable entera de tamaño máximo $2^{63}-1$ tanto positivo como negativo.
Se decidió no implementar el exponente con tamaño dinámico ya que al ser éste un número relativamente grande, el grupo consideró que para el presente trabajo esto no era necesario.

En cuanto a la base, planteamos tres alternativas: hacerlo en base 10, en base 2 y en base 256.

En principio, el motivo de la elección de la base 10 era, la facilidad para manejarse entre lo que uno puede ver en la mantisa y los números
que uno maneja en forma natural. Además las funciones de suma y multiplicación se simplificarían bastante.

En cuanto a la base 2 y la base 256, son parecidas, la única diferencia que tiene es que en la base 256, 
los dígitos consisten en 8 bits, mientras en la base 2, cada bit es un dígito.

Finalmente, las razones por la cual elegimos utilizar la base 256 son varias. En cuanto a la comparación con la base 10, las operaciones elementales que se realizan entre los dígitos en la suma y la multiplicación de la base 10, son más costosas que las operaciones lógicas que se pueden realizar a nivel de bit en la base 256. Estas diferencias de costos, pueden no influir en pocas operaciones, pero cuando el volumen de operaciones realizadas es considerable como es el caso de este proyecto, el tiempo puede resultan significativamente inferior.\\

En cuanto a la comparación con la base 2, la única razón por la que se decidió usar la base 256,
es por una limitación del lenguaje de programación usado, C++, cuya unidad mínima de almacenamiento/direccionamiento es de 1 byte. Con lo cual para en el caso de base 2, por cada dígito que tenga la mantisa se desperdiciarán 7 bits de memoria lo cual supone un desperdicio de memoria importante cuando la ésta se va extendiendo. Mientas que en 
el caso de base 256, el desperdicio de memoria jamás es mayor a 7 bits sin importar la cantidad
de dígitos.\\

El inconveniente que trae hacerlo en otra base que no es la que se recibe por parámetros (se
recibe en base 10) es que en este cambio hay números que pueden pasar a ser periódicos en esta representación.

Para esto se decidió truncar el número en un dígito máximo, sin embargo es tan grande que no influye
en la precisión. Además una vez pasado al formato elegido para la representación, la mantisa sí puede seguir agrandándose de la forma en la que se indica en la sección anterior.

\subsection{Complejos}

Para modelar a los números complejos, se decidió tomarlos como una dupla de Float, de esta forma depende íntegramente de la aritmética descripta anteriormente.\\
Esta dupla tiene en su primer componente la parte real del los complejos y en la segunda la parte imaginaria, acorde con la definición de números complejos pensado como 2-uplas de números reales.

Lo importante a destacar es que en los algoritmos, intentamos utilizar los que menos operaciones
impliquen y más estables sean. Un ejemplo de esto es cuando se realiza la operación para hacer
un complejo al cuadrado, que la parte real $(c.Re()^2 - c.Im()^2)$ y analizamos
que lo que conviene hacer es $(c.Re()+c.Im())*(c.Re()-c.Im())$ que implica funciones más rápidas
y estables.

\subsection{Mandelbrot}

\subsubsection{Colores}

Recordando la definición del conjunto de Mandlebrot:
$$M = \left\{c\in \mathbb C: |P_c^n(0)| \le s \: \forall \: n \in \mathbb N \right\}$$
y de la secuencia: $(0, p_c(0), p_c(p_c(0)), ... )$ que refleja las aplicaciones del polinomio $P_c$, decidimos graficar un mapa de calor del conjunto de Mandelbrot.

Un mapa de calor es una representación que utiliza colores para mostrar el valor tomado por una función de dos variables: en este caso, las coordenadas $(z_{re},z_{im})$ (con $z \in \mathbb{C}$) y el número de iteración en las que este punto diverge o converge a un valor menor que la cota.

En nuestro caso definimos un \emph{gradiente de color}\cite{gradiente} que es una función que dado uno o varios colores se encarga de calcular en forma gradual los valores intermedios de color desde unos a otros.

Para ello se tomó la representación de 24 bits \emph{RGB} (Red-Green-Blue) que se construye considerando la tupla $(r,g,b)$ en la que cada componente de la misma tiene valores enteros en el intervalo $[0,255]$ que reflejan la intensidad de cada tono en el color producido al final.

De esta manera, como la cantidad de iteraciones es acotada por un número $n$ para evitar ciclos infinitos, se dividió el segmento $[0,n]$ en forma arbitraria y se definieron seis colores para entonces utilizar la función de color que se encarga de pintar el punto del plano. Dicha función trabaja de la siguiente manera: si el punto en cuestión diverge, entonces se toma la iteración en la que el mismo se pasó de la cota y este es coloreado de acuerdo a alguno de los colores definidos o de sus tonos intermedios. En caso de que el punto se mantenga siempre por debajo de la cota establecida al cabo de $n$ iteraciones, entonces el mismo se pinta de negro.